// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "content/browser/child_process_launcher.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/shell/browser/shell.h"

namespace {

class MockChildProcessLauncherClient
    : public content::ChildProcessLauncher::Client {
public:
    MockChildProcessLauncherClient()
        : client_(nullptr)
        , simulate_failure_(false)
    {
    }

    void OnProcessLaunched() override
    {
        if (simulate_failure_)
            client_->OnProcessLaunchFailed(content::LAUNCH_RESULT_FAILURE);
        else
            client_->OnProcessLaunched();
    };

    void OnProcessLaunchFailed(int error_code) override
    {
        client_->OnProcessLaunchFailed(error_code);
    };

    content::ChildProcessLauncher::Client* client_;
    bool simulate_failure_;
};

}

namespace content {

class ChildProcessLauncherBrowserTest : public ContentBrowserTest {
};

class StatsTableBrowserTest : public ChildProcessLauncherBrowserTest {
public:
    void SetUpCommandLine(base::CommandLine* command_line) override
    {
        command_line->AppendSwitch(switches::kEnableStatsTable);
    }
};

IN_PROC_BROWSER_TEST_F(StatsTableBrowserTest, StartWithStatTable)
{
    NavigateToURL(shell(), GURL("about:blank"));
}

IN_PROC_BROWSER_TEST_F(ChildProcessLauncherBrowserTest, ChildSpawnFail)
{
    GURL url("about:blank");
    Shell* window = shell();
    MockChildProcessLauncherClient* client(nullptr);

    // Navigate once and simulate a process failing to spawn.
    TestNavigationObserver nav_observer1(window->web_contents(), 1);
    client = new MockChildProcessLauncherClient;
    window->LoadURL(url);
    client->client_ = static_cast<RenderProcessHostImpl*>(
        window->web_contents()->GetRenderProcessHost())
                          ->child_process_launcher_->ReplaceClientForTest(client);
    client->simulate_failure_ = true;
    nav_observer1.Wait();
    delete client;
    NavigationEntry* last_entry = shell()->web_contents()->GetController().GetLastCommittedEntry();
    // Make sure we didn't navigate.
    CHECK(!last_entry);

    // Navigate again and let the process spawn correctly.
    TestNavigationObserver nav_observer2(window->web_contents(), 1);
    window->LoadURL(url);
    nav_observer2.Wait();
    last_entry = shell()->web_contents()->GetController().GetLastCommittedEntry();
    // Make sure that we navigated to the proper URL.
    CHECK(last_entry && last_entry->GetPageType() == PAGE_TYPE_NORMAL);
    CHECK(shell()->web_contents()->GetLastCommittedURL() == url);

    // Navigate again, using the same renderer.
    url = GURL("data:text/html,dataurl");
    TestNavigationObserver nav_observer3(window->web_contents(), 1);
    window->LoadURL(url);
    nav_observer3.Wait();
    last_entry = shell()->web_contents()->GetController().GetLastCommittedEntry();
    // Make sure that we navigated to the proper URL.
    CHECK(last_entry && last_entry->GetPageType() == PAGE_TYPE_NORMAL);
    CHECK(shell()->web_contents()->GetLastCommittedURL() == url);
}

} // namespace content
